package cn.nukkit.inventory;

import cn.nukkit.Player;
import cn.nukkit.item.Item;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * author: MagicDroidX
 * Nukkit Project
 * <br>
 * @author wanne (doc-api-chs )
 * 物品栏接口<br>
 * 更多物品栏相关信息：
 * https://minecraft-zh.gamepedia.com/%E7%89%A9%E5%93%81%E6%A0%8F<br>
 * https://minecraft.gamepedia.com/Inventory
 */
public interface Inventory {

    int MAX_STACK = 64;

    /** 凹槽数量*/
    int getSize();

    /** 最大可叠加数量，这个应该看具体时什么物品<br>
     * NBT 物品不能和正常物品叠加
     */
    int getMaxStackSize();

    /** 设置最大凹槽数量*/
    void setMaxStackSize(int size);

    /** 获取物品栏名*/
    String getName();

    /** 获取物品栏标题*/
    String getTitle();

    /** 获取物品栏内的某个物品*/
    Item getItem(int index);

    /** 设置物品栏内的某个物品*/
    default boolean setItem(int index, Item item) {
        return setItem(index, item, true);
    }
    
    /** 设置物品栏内的某个物品（末尾的参数不知道什么意思，待确定）*/
    boolean setItem(int index, Item item, boolean send);

    /** 追加物品*/
    Item[] addItem(Item... slots);

    /** 检查是否能继续添加某个物品*/
    boolean canAddItem(Item item);

    /** 移除物品（返回失败的物品，具体查看 {@link cn.nukkit.inventory.BaseInventory#removeItem}）*/
    Item[] removeItem(Item... slots);

    /** （待确定，初步猜测是所有的物品信息）*/
    Map<Integer, Item> getContents();

    /** 替换物品栏里的物品*/
    void setContents(Map<Integer, Item> items);

    /** 给玩家发送物品栏信息的数据包*/
    void sendContents(Player player);

    /** 给玩家发送物品栏信息的数据包*/
    void sendContents(Player... players);

    /** 给玩家发送物品槽信息的数据包*/
    void sendContents(Collection<Player> players);

    /** 给玩家发送物品槽信息的数据包*/
    void sendSlot(int index, Player player);

    /** 给玩家发送物品槽信息的数据包*/
    void sendSlot(int index, Player... players);

    /** 给玩家发送物品槽信息的数据包*/
    void sendSlot(int index, Collection<Player> players);

    /** 判断是否包含某个物品*/
    boolean contains(Item item);

    /** 待确定*/
    Map<Integer, Item> all(Item item);

    /** 获取第一个物品下标，非精准获取*/
    default int first(Item item) {
        return first(item, false);
    }

    /** 获取第一个物品下标，是否精准获取
     * @para exact 是否精准获取
     */
    int first(Item item, boolean exact);
    
    /** 获取第一个没有存放物品位置的下标*/
    int firstEmpty(Item item);

    /** 减少某个物品槽内物品的数量*/
    void decreaseCount(int slot);

    /** 移除某个物品*/
    void remove(Item item);

    /** 清除物品槽内的物品*/
    default boolean clear(int index) {
        return clear(index, true);
    }

    /** 清除物品槽内的物品信息，是否发送物品槽信息数据包*/
    boolean clear(int index, boolean send);

    /** 清除所有*/
    void clearAll();

    /** 是否已经满了（和具体实现有关）*/
    boolean isFull();

    /** 是否为空*/
    boolean isEmpty();

    /** 获取正在查看此物品栏的所有玩家*/
    Set<Player> getViewers();

    /** 获取物品栏类型*/
    InventoryType getType();

    /** 获取物品栏所有者*/
    InventoryHolder getHolder();

    /** 玩家打开物品栏处理器*/
    void onOpen(Player who);

    /** 玩家打开物品栏事件，可能会唤起其它事件，最后可能会调用 {@link #onOpen(Player)}*/
    boolean open(Player who);

    /** 玩家关闭物品栏事件，可能会唤起其它事件，最后可能会调用 {@link #onClose(Player)}*/
    void close(Player who);

    /** 玩家关闭物品栏处理器*/
    void onClose(Player who);

    /** 物品栏内插槽的物品发生 处理器*/
    void onSlotChange(int index, Item before, boolean send);
}
